package upload;


import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.TableItem;

import ui.FileUploadUI;
import util.Utility;

public class UploadEngine extends Thread implements PropertyChangeListener
{

	UploadInfoBean uploadFileInfoBean = null; 
	TableItem tableItem;
	long[] startPosition; 
	long[] endPosition; 
	long[] oriStartPosition;
	ClientFileHandle[] uploadThread; 
	long fileLength; 
	boolean isFirstDownload = true; 
	boolean bStop = false; 
	File file;
	File tmpFile; 
	DataOutputStream output; 

	public UploadEngine(UploadInfoBean bean,TableItem newItemTableItem) throws IOException
	{
		uploadFileInfoBean = bean;
		this.tableItem = newItemTableItem;
		file = new File(bean.getFilePath());
		if (!file.exists()){
			throw new FileNotFoundException("[" + bean.getFilePath() +"] is not exist!");
		}
		
		fileLength = file.length();
		if(tableItem != null)
			Display.getDefault().syncExec(new UpdateTableItem(tableItem, uploadFileInfoBean.getFileName(),fileLength/1000+"kb",null,null));
		
		
		tmpFile = new File(bean.getFilePath() + ".up");
		if (tmpFile.exists())
		{
			isFirstDownload = false;
			read_positon();
		}
		else
		{
			startPosition = new long[bean.getThreadNum()];
			endPosition = new long[bean.getThreadNum()];
			
			for (int i = 0, length = startPosition.length; i < length; i++){
				startPosition[i] = (long) (i * (fileLength / length));
			}
			for (int i = 0, length = endPosition.length; i < length - 1; i++){
				endPosition[i] = startPosition[i + 1];
			}
			endPosition[endPosition.length - 1] = fileLength;
		}
		
		oriStartPosition = new long[startPosition.length];
		for (int i = 0, length = startPosition.length; i < length; i++){
			oriStartPosition[i] = (long) (i * (fileLength / length));
		}
		
		StringBuilder sb = new StringBuilder();
		for(int i=0;i<startPosition.length;i++){
			if(i == 0)
				sb.append(startPosition[i]);
			else
				sb.append("|" + startPosition[i]);
		}
		StringBuilder urlStr = new StringBuilder(FileUploadUI.path);
		urlStr.append("/Server?type=param&name=");
		urlStr.append(Utility.URLEncode(bean.getFileName()));
		urlStr.append("&thread=");
		urlStr.append(startPosition.length);
		urlStr.append("&point="+sb.toString());
		Utility.send(urlStr.toString());
	}

	public void run()
	{
		try
		{
			
			long speed = 0;
			
			uploadThread = new ClientFileHandle[startPosition.length];
			for (int i = 0; i < startPosition.length; i++)
			{
				uploadThread[i] = new ClientFileHandle(
						uploadFileInfoBean.getFilePath(),
						uploadFileInfoBean.getFileName(), 
						startPosition[i], 
						endPosition[i], 
						i);
				uploadThread[i].addPropertyChangeListener(this);
				
				System.err.println("Thread " + i + " , nStartPos = " + startPosition[i] + ", nEndPos = " + endPosition[i]);
				uploadThread[i].start();
				speed += startPosition[i];
			}
			
			
			boolean breakWhile = false;
			long speed2 = 0;
			while (!bStop)
			{
				write_position();
				Utility.sleep(1000);
				speed2 = 0;
				long tmp = 0;
				for (int i = 0; i < startPosition.length; i++){
					speed2 += uploadThread[i].getStartPos();
					tmp += uploadThread[i].getStartPos() - oriStartPosition[i];
				}
				
//				if(tmp>fileLength)
//					tmp = fileLength;

				if(tableItem != null)
					Display.getDefault().syncExec(new UpdateTableItem(tableItem, null,null,(speed2 - speed)/1000 + "kb",tmp * 100 / fileLength + "%"));
				speed = speed2;
				
				breakWhile = true;
				for (int i = 0,length = startPosition.length; i < length; i++)
				{
					if (!uploadThread[i].isStop())
					{
						breakWhile = false;
					}
				}
				if (breakWhile)
					break;
				
			}

			if(bStop){
				System.err.println("stop upload...");
				if(tableItem != null)
					Display.getDefault().syncExec(new UpdateTableItem(tableItem, null,null,"停止"));
			}
			else{
				tmpFile.delete();
				System.err.println("finish upload...");
				if(tableItem != null)
					Display.getDefault().syncExec(new UpdateTableItem(tableItem, null,null,"完成"));
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		finally{
			String encodeName = uploadFileInfoBean.getFileName();
			encodeName = Utility.URLEncode(uploadFileInfoBean.getFileName());

			StringBuilder urlStr = new StringBuilder(FileUploadUI.path);
			urlStr.append("/Server?type=close&name=");
			urlStr.append(encodeName);
			Utility.send(urlStr.toString());
		}
	}
	
	public void propertyChange(PropertyChangeEvent evt)
	{
		ClientFileHandle cfh = (ClientFileHandle)evt.getNewValue();
		if(cfh == null)
			return;
		
		Utility.log( cfh.getID() + ":" + evt.getPropertyName());
		
		if(ClientFileHandle.FINISH.endsWith(evt.getPropertyName())){
			if(cfh.getID() < uploadThread.length && cfh.getID() >= 0){
				uploadThread[cfh.getID()].stopUpload();
			}
		}
	}

	
	private void write_position()
	{
		try
		{
			output = new DataOutputStream(new FileOutputStream(tmpFile));
			output.writeInt(startPosition.length);
			for (int i = 0; i < startPosition.length; i++)
			{
				output.writeLong(uploadThread[i].getStartPos());
				output.writeLong(uploadThread[i].getEndPos());
			}
			output.close();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	
	private void read_positon()
	{
		try
		{
			DataInputStream input = new DataInputStream(new FileInputStream(tmpFile));
			int nCount = input.readInt();
			startPosition = new long[nCount];
			endPosition = new long[nCount];
			for (int i = 0; i < startPosition.length; i++)
			{
				startPosition[i] = input.readLong();
				endPosition[i] = input.readLong();
			}
			input.close();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}


	
	public void stopUpload()
	{
		bStop = true;
		for (int i = 0; i < startPosition.length; i++)
			uploadThread[i].stopUpload();

	}

	public long[] getStartPosition()
	{
		return startPosition.clone();
	}

	public long[] getEndPosition()
	{
		return endPosition.clone();
	}
	
	protected class UpdateTableItem implements Runnable {
		
		TableItem tableItem;
		String[] s;
		
		public UpdateTableItem(TableItem tableItem, String...s){
			this.tableItem = tableItem;
			this.s = s;
		}
		
		public void run() {
			for(int i=0,len=s.length;i<len;i++){
				if(s[i]!=null){
					tableItem.setText(i,s[i]);
				}
			}
		}
		
	}


}
